﻿using System;
using System.Linq;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Data;
using System.Windows.Input;
using System.Windows.Media;
using System.Collections.Specialized;

namespace UBCon.Ribbon
{
    using UBCon.Core.Commands;
    using UBCon.Ribbon.Interfaces;
    using System.Diagnostics;

    [StyleTypedProperty(Property = "ItemContainerStyle", StyleTargetType = typeof(RibbonGalleryItem))]
    [TemplatePart(Name = PART_RibbonGalleryPanelName, Type = typeof(Panel))]
    [TemplatePart(Name = PART_UpButtonName, Type = typeof(System.Windows.Controls.Primitives.ButtonBase))]
    [TemplatePart(Name = PART_DownButtonName, Type = typeof(System.Windows.Controls.Primitives.ButtonBase))]
    [TemplatePart(Name = PART_ThirdButtonName, Type = typeof(System.Windows.Controls.Primitives.ButtonBase))]
    [TemplatePart(Name = PART_RibbonGalleryPopupName, Type = typeof(Popup))]
    /// <summary>
    /// List of selectable items.
    /// </summary>
    public class RibbonGallery:ListBox, IRibbonControl
    {
        #region Constructors

        /// <summary>
        /// Default static constructor.
        /// </summary>
        static RibbonGallery()
        {
            Type ownerType = typeof(RibbonGallery);

            RibbonGallery.DefaultStyleKeyProperty.OverrideMetadata(ownerType, new FrameworkPropertyMetadata(ownerType));

            KeyboardNavigation.DirectionalNavigationProperty.OverrideMetadata(ownerType, new FrameworkPropertyMetadata(KeyboardNavigationMode.Cycle));

            RibbonGallery.FocusVisualStyleProperty.OverrideMetadata(ownerType, new FrameworkPropertyMetadata(null));

            RibbonGallery.ItemsSourceProperty.OverrideMetadata(ownerType,
                new FrameworkPropertyMetadata
                    (
                    null,
                    new PropertyChangedCallback(OnItemsSourceChanged)));
        }

        /// <summary>
        /// Default constructor.
        /// </summary>
        public RibbonGallery() : base() 
        {
            RegisterCommands();

            DropDownGalleries = new ObservableCollection<RibbonGallery>();

            DropDownGalleries.CollectionChanged += new NotifyCollectionChangedEventHandler(OnDropDownGalleriesCollectionChanged);

            //ItemContainerGenerator.StatusChanged += ItemContainerGenerator_StatusChanged;

            Loaded += OnRibbonGalleryLoaded;
        }

        #endregion

        #region Properties

        /// <summary>
        /// Gets or sets a boolean value indicating whether Popup stays open when item is selected.
        /// This is a dependency property.
        /// </summary>
        public bool StaysOpenOnSelection
        {
            get { return (bool)GetValue(StaysOpenOnSelectionProperty); }
            set { SetValue(StaysOpenOnSelectionProperty, value); }
        }

        // Using a DependencyProperty as the backing store for StaysOpenOnSelection.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty StaysOpenOnSelectionProperty =
            DependencyProperty.Register("StaysOpenOnSelection", typeof(bool), typeof(RibbonGallery), 
            new PropertyMetadata(false));

        /// <summary>
        /// Identifies current start index.
        /// </summary>
        internal int CurrentIndex
        {
            get { return (int)GetValue(CurrentIndexProperty); }
            set { SetValue(CurrentIndexProperty, value); }
        }

        // Using a DependencyProperty as the backing store for CurrentIndex.  This enables animation, styling, binding, etc...
        internal static readonly DependencyProperty CurrentIndexProperty =
            DependencyProperty.Register("CurrentIndex", typeof(int), typeof(RibbonGallery),
            new FrameworkPropertyMetadata(-1, 
                FrameworkPropertyMetadataOptions.BindsTwoWayByDefault | FrameworkPropertyMetadataOptions.Journal));

        
        /// <summary>
        /// Gets or sets a boolean value indicating whether RibbonGallery is in minimized state or not.
        /// This is a dependency property.
        /// </summary>
        internal bool IsMinimized
        {
            get { return (bool)GetValue(IsMinimizedProperty); }
            set { SetValue(IsMinimizedProperty, value); }
        }

        // Using a DependencyProperty as the backing store for IsMinimized.  This enables animation, styling, binding, etc...
        internal static readonly DependencyProperty IsMinimizedProperty =
            DependencyProperty.Register("IsMinimized", typeof(bool), typeof(RibbonGallery), new FrameworkPropertyMetadata(false));

        /// <summary>
        /// Gets or sets ImageSource when RibbonGallery is minimized.
        /// </summary>
        [Bindable(true),
        ReadOnly(false),
        Category("Appearence")]
        public ImageSource Image
        {
            get { return (ImageSource)GetValue(ImageProperty); }
            set { SetValue(ImageProperty, value); }
        }

        // Using a DependencyProperty as the backing store for Image.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty ImageProperty = RibbonButton.ImageProperty.AddOwner(typeof(RibbonGallery));

        /// <summary>
        /// Gets or sets a boolean value which indicates whether control is in RibbonGroup or not.
        /// </summary>
        internal bool IsInGroup
        {
            get { return (bool)GetValue(IsInGroupProperty); }
            set { SetValue(IsInGroupProperty, value); }
        }

        // Using a DependencyProperty as the backing store for IsInGroup.  This enables animation, styling, binding, etc...
        internal static readonly DependencyProperty IsInGroupProperty =
            DependencyProperty.Register("IsInGroup", typeof(bool), typeof(RibbonGallery),
            new PropertyMetadata(
                false,
                new PropertyChangedCallback(OnIsInGroupChanged)));

        /// <summary>
        /// Gets os sets visible items count. 
        /// </summary>
        public int VisibleItemsCount
        {
            get { return (int)GetValue(VisibleItemsCountProperty); }
            set { SetValue(VisibleItemsCountProperty, value); }
        }

        // Using a DependencyProperty as the backing store for VisibleItemsCount.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty VisibleItemsCountProperty =
            DependencyProperty.Register("VisibleItemsCount", typeof(int),
            typeof(RibbonGallery),
            new FrameworkPropertyMetadata(3, new PropertyChangedCallback(OnVisibleItemsCountChanged),
                new CoerceValueCallback(CoerceVisibleItemsCount)));

        /// <summary>
        /// Gets or sets control's header.
        /// </summary>
        public object Header
        {
            get { return (object)GetValue(HeaderProperty); }
            set { SetValue(HeaderProperty, value); }
        }

        // Using a DependencyProperty as the backing store for Header.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty HeaderProperty =
            DependencyProperty.Register("Header", typeof(object), typeof(RibbonGallery), 
            new FrameworkPropertyMetadata((object)null));

        /// <summary>
        /// Gets or sets header's string format.
        /// This is a dependency property.
        /// </summary>
        public string HeaderStringFormat
        {
            get { return (string)GetValue(HeaderStringFormatProperty); }
            set { SetValue(HeaderStringFormatProperty, value); }
        }

        // Using a DependencyProperty as the backing store for HeaderStringFormat.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty HeaderStringFormatProperty =
            DependencyProperty.Register("HeaderStringFormat", typeof(string), typeof(RibbonGallery), 
            new PropertyMetadata(null));

        [Bindable(true),
        ReadOnly(false),
        Category("Appearance")]
        /// <summary>
        /// Gets or sets header's DataTemplate which descibes the visual structure of a data object..
        /// This is a dependency property.
        /// </summary>
        public DataTemplate HeaderTemplate
        {
            get { return (DataTemplate)GetValue(HeaderTemplateProperty); }
            set { SetValue(HeaderTemplateProperty, value); }
        }

        // Using a DependencyProperty as the backing store for HeaderTemplate.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty HeaderTemplateProperty =
            DependencyProperty.Register("HeaderTemplate", typeof(DataTemplate), typeof(RibbonGallery), 
            new PropertyMetadata(null));

        /// <summary>
        /// Gets or sets DataTemplateSelector for header which provides a way to choose a System.Windows.DataTemplate based on the data object and the data-bount element.
        /// This is a dependency property.
        /// </summary>
        public DataTemplateSelector HeaderTemplateSelector
        {
            get { return (DataTemplateSelector)GetValue(HeaderTemplateSelectorProperty); }
            set { SetValue(HeaderTemplateSelectorProperty, value); }
        }

        // Using a DependencyProperty as the backing store for HeaderTemplateSelector.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty HeaderTemplateSelectorProperty =
            DependencyProperty.Register("HeaderTemplateSelector", typeof(DataTemplateSelector), typeof(RibbonGallery), 
            new PropertyMetadata(null));

        /// <summary>
        /// Gets or sets header's brush.
        /// </summary>
        [Bindable(true),
        ReadOnly(false),
        Category("Appearance")]
        public Brush HeaderBackground
        {
            get { return (Brush)GetValue(HeaderBackgroundProperty); }
            set { SetValue(HeaderBackgroundProperty, value); }
        }

        // Using a DependencyProperty as the backing store for HeaderBackground.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty HeaderBackgroundProperty =
            DependencyProperty.Register("HeaderBackground", typeof(Brush), typeof(RibbonGallery), 
            new PropertyMetadata((Brush)null));

        /// <summary>
        /// Gets or sets root menu of this control.
        /// </summary>
        public DropDownButtonBase ParentMenu
        {
            get { return (DropDownButtonBase)GetValue(ParentMenuProperty); }
            set { SetValue(ParentMenuProperty, value); }
        }

        // Using a DependencyProperty as the backing store for ParentMenu.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty ParentMenuProperty =
            DependencyProperty.Register("ParentMenu", typeof(DropDownButtonBase), typeof(RibbonGallery),
            new PropertyMetadata((DropDownButtonBase)null));

        /// <summary>
        /// Gets or sets a boolean value which indicates RibbonGallery's drop-down is currently open or not.
        /// This is dependency property.
        /// </summary>
        [Browsable(false),
        Bindable(true),
        ReadOnly(false),
        Category("Behaviour")]
        public bool IsDropDownOpen
        {
            get { return (bool)GetValue(IsDropDownOpenProperty); }
            set { SetValue(IsDropDownOpenProperty, value); }
        }

        // Using a DependencyProperty as the backing store for IsDropDownOpen.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty IsDropDownOpenProperty =
            DependencyProperty.Register("IsDropDownOpen", typeof(bool), typeof(RibbonGallery),
            new FrameworkPropertyMetadata(
                false,
                 FrameworkPropertyMetadataOptions.BindsTwoWayByDefault | FrameworkPropertyMetadataOptions.Journal,
                 new PropertyChangedCallback(OnIsDropDownOpenChanged)));

        /// <summary>
        /// Gets or sets a collection of RibbonGallery control.
        /// </summary>
        [Browsable(false),
        Bindable(false),
        ReadOnly(false)]
        public ObservableCollection<RibbonGallery> DropDownGalleries
        {
            get { return (ObservableCollection<RibbonGallery>)GetValue(DropDownGalleriesProperty); }
            set { SetValue(DropDownGalleriesProperty, value); }
        }

        // Using a DependencyProperty as the backing store for DropDownGalleries.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty DropDownGalleriesProperty =
            DependencyProperty.Register("DropDownGalleries", typeof(ObservableCollection<RibbonGallery>),
            typeof(RibbonGallery), new PropertyMetadata((ObservableCollection<RibbonGallery>)null));

        [Bindable(true),
        Category("Behaviour"),
        Browsable(true)]
        /// <summary>
        /// Gets or sets a boolean value which indicates whether the drop-down is resizable or not.
        /// This is a dependency property.
        /// </summary>
        public bool CanResizeDropDown
        {
            get { return (bool)GetValue(CanResizeDropDownProperty); }
            set { SetValue(CanResizeDropDownProperty, value); }
        }

        // Using a DependencyProperty as the backing store for CanResizeDropDown.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty CanResizeDropDownProperty =
            DependencyProperty.Register("CanResizeDropDown", typeof(bool), typeof(RibbonGallery),
            new FrameworkPropertyMetadata(false, 
                FrameworkPropertyMetadataOptions.BindsTwoWayByDefault | FrameworkPropertyMetadataOptions.Journal));

        /// <summary>
        /// Gets or sets horizontal bar's visibility value. 
        /// This is a dependency property.
        /// </summary>
        public ScrollBarVisibility HorizontalScrollBarVisibility
        {
            get { return (ScrollBarVisibility)GetValue(HorizontalScrollBarVisibilityProperty); }
            set { SetValue(HorizontalScrollBarVisibilityProperty, value); }
        }

        // Using a DependencyProperty as the backing store for HorizontalScrollBarVisibility.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty HorizontalScrollBarVisibilityProperty =
            DependencyProperty.Register("HorizontalScrollBarVisibility", typeof(ScrollBarVisibility), typeof(RibbonGallery), new PropertyMetadata(ScrollBarVisibility.Disabled));

        /// Gets or sets vertical bar's visibility value. 
        /// This is a dependency property.
        public ScrollBarVisibility VerticalScrollBarVisibility
        {
            get { return (ScrollBarVisibility)GetValue(VerticalScrollBarVisibilityProperty); }
            set { SetValue(VerticalScrollBarVisibilityProperty, value); }
        }

        // Using a DependencyProperty as the backing store for VerticalScrollBarVisibility.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty VerticalScrollBarVisibilityProperty =
            DependencyProperty.Register("VerticalScrollBarVisibility", typeof(ScrollBarVisibility), typeof(RibbonGallery), new PropertyMetadata(ScrollBarVisibility.Disabled));

        /// <summary>
        /// Gets or sets a double value for maximum width of the drop-down.
        /// This is a dependency property.
        /// </summary>
        public double MaxDropDownWidth
        {
            get { return (double)GetValue(MaxDropDownWidthProperty); }
            set { SetValue(MaxDropDownWidthProperty, value); }
        }

        // Using a DependencyProperty as the backing store for MaxDropDownWidth.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty MaxDropDownWidthProperty = DropDownMenuItem.MaxDropDownWidthProperty.AddOwner(typeof(RibbonGallery));


        /// <summary>
        /// Gets or sets maximum value of drop-down's height.
        /// This is a dependency property.
        /// </summary>
        public double MaxDropDownHeight
        {
            get { return (double)GetValue(MaxDropDownHeightProperty); }
            set { SetValue(MaxDropDownHeightProperty, value); }
        }

        // Using a DependencyProperty as the backing store for MaxDropDownHeight.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty MaxDropDownHeightProperty =
            DependencyProperty.Register("MaxDropDownHeight", typeof(double), typeof(RibbonGallery), new PropertyMetadata(500.0));

        /// <summary>
        /// Gets or sets minimum value of drop-down's height.
        /// This is a dependency property.
        /// </summary>
        public double MinDropDownHeight
        {
            get { return (double)GetValue(MinDropDownHeightProperty); }
            set { SetValue(MinDropDownHeightProperty, value); }
        }

        // Using a DependencyProperty as the backing store for MinDropDownHeight.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty MinDropDownHeightProperty =
            DependencyProperty.Register("MinDropDownHeight", typeof(double), typeof(RibbonGallery), new PropertyMetadata(100.0D));

        
        /// <summary>
        /// Gets a boolean value which indicates whether down galleries' host panel is avaliable or not.
        /// </summary>
        internal bool IsDownGalleriesPanelAvaliable
        {
            get
            {
                return dropDownGalleriesPanel != null;
            }
        }

        #endregion

        #region Depenency Property Changed Callbacks

        /// <summary>
        /// Invoked whenever ItemsSource property changes. 
        /// </summary>
        /// <param name="sender">Type: System.Windows.DependencyObject. The DependencyObject on which the property has changed value.</param>
        /// <param name="e">Type: System.Windows.DependencyPropertyChangedEventArgs. Event data that is issued by any event that tracks changes to the effective value of this property.</param>
        private static void OnItemsSourceChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
        {
            RibbonGallery gallery = (RibbonGallery)sender;
            if (gallery.IsInGroup)
            {
                if (e.NewValue == null)
                {
                    //clearing all stored items when ItemSource is null
                    gallery.CurrentIndex = -1;

                    gallery.ClearValue(SelectedIndexProperty);
                }
                else 
                {
                    gallery.CurrentIndex = 0;
                }
            }
        }

        /// <summary>
        /// Invoked whenever IsDropDownOpen property changes.
        /// </summary>
        /// <param name="sender">Type: System.Windows.DependencyObject. The DependencyObject on which the property has changed value.</param>
        /// <param name="e">Type: System.Windows.DependencyPropertyChangedEventArgs. Event data that is issued by any event that tracks changes to the effective value of this property.</param>
        private static void OnIsDropDownOpenChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e) { }

        /// <summary>
        /// Invoked whenever VisibleItemsCount property changes.
        /// </summary>
        /// <param name="sender">Type: System.Windows.DependencyObject. The DependencyObject on which the property has changed value.</param>
        /// <param name="e">Type: System.Windows.DependencyPropertyChangedEventArgs. Event data that is issued by any event that tracks changes to the effective value of this property.</param>
        private static void OnVisibleItemsCountChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
        {
            RibbonGallery gallery = (RibbonGallery)sender;
            gallery.CurrentIndex = 0;
        }

        /// <summary>
        /// Coerces VisibleItems property.
        /// </summary>
        /// <param name="sender">Type: System.Windows.DependencyObject. The object that the property exists on. When the callback is invoked, the property system will pass this value.</param>
        /// <param name="value">Type: System.Object. The new value of the property, prior to any coercion attempt.</param>
        /// <returns>Type: System.Object. The coerced value (with appropriate type). </returns>
        private static object CoerceVisibleItemsCount(DependencyObject sender, object value)
        {
            int visItemCount = (int)value;

            if (visItemCount <= 0)
            {
                return 1;
            }
            return value;
        }

        /// <summary>
        /// Invoked when IsInGroup property changes.
        /// </summary>
        /// <param name="sender">Type: System.Windows.DependencyObject. The DependencyObject on which the property has changed value.</param>
        /// <param name="e">Type: System.Windows.DependencyPropertyChangedEventArgs. Event data that is issued by any event that tracks changes to the effective value of this property.</param>
        private static void OnIsInGroupChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e) 
        {
            RibbonGallery gallery = (RibbonGallery)sender;
            bool newValue = (bool)e.NewValue;
            bool oldvalue = !newValue;

            Mouse.RemovePreviewMouseDownOutsideCapturedElementHandler(gallery, gallery.OnMouseDownOutsideCaptured);

            if (newValue)
            {
                Mouse.AddPreviewMouseDownOutsideCapturedElementHandler(gallery, new MouseButtonEventHandler(gallery.OnMouseDownOutsideCaptured));
            }
        }
        #endregion

        #region Overrides

        /// <summary>
        /// Called when the selection changes.
        /// </summary>
        /// <param name="e">Event data for the event.</param>
        protected override void OnSelectionChanged(SelectionChangedEventArgs e)
        {
            base.OnSelectionChanged(e);
            if (SelectedIndex >= 0)
            {
                CurrentIndex = (int)(SelectedIndex / VisibleItemsCount);
            }
            else 
            {
                if (HasItems) 
                {
                    CurrentIndex = 0;
                }
            }

            UpdateCanExecuteState();

            if (!IsInGroup && ParentRibbonGallery != null)
            {
                if (ParentRibbonGallery.IsDropDownOpen)
                {
                    ParentRibbonGallery.CloseDropDown();
                }
            }
        }

        /// <summary>
        ///Creates or identifies the element that is used to display the given item.
        /// </summary>
        /// <returns>Type: System.Windows.DependencyObject. The element that is used to display the given item.</returns>
        protected override DependencyObject GetContainerForItemOverride()
        {
            RibbonGalleryItem gItem = new RibbonGalleryItem();

            if (gItem.ParentGallery == null) 
            {
                gItem.ParentGallery = this;
            }

            return gItem;
        }

        /// <summary>
        /// Determines if the specified item is (or is eligible to be) its own ItemContainer. 
        /// (Overrides ItemsControl.IsItemItsOwnContainerOverride(Object).)
        /// </summary>
        /// <param name="item">Specified item.</param>
        /// <returns>true if the item is its own ItemContainer; otherwise, false.</returns>
        protected override bool IsItemItsOwnContainerOverride(object item)
        {
            bool isValidItem = item is RibbonGalleryItem;

            if (isValidItem)
            {
                RibbonGalleryItem gItem = item as RibbonGalleryItem;
                if (gItem.ParentGallery == null)
                {
                    gItem.ParentGallery = this;
                }
            }
            return isValidItem;
        }

        /// <summary>
        /// Invoked whenever application code or internal processes (such as a rebuilding layout pass) call ApplyTemplate. 
        /// In simplest terms, this means the method is called just before a UI element displays in  app.  
        /// </summary>
        public override void OnApplyTemplate()
        {
            if (resizeThumb != null) 
            {
                resizeThumb.DragDelta -= OnThumbDragDelta;
            }
            _downButton = GetTemplateChild(PART_DownButtonName) as System.Windows.Controls.Primitives.ButtonBase;

            _upButton = GetTemplateChild(PART_UpButtonName) as System.Windows.Controls.Primitives.ButtonBase;

            _thirdButton = GetTemplateChild(PART_ThirdButtonName) as ButtonBase;

            _popup = GetTemplateChild(PART_RibbonGalleryPopupName) as Popup;

            dropDownGalleriesPanel = GetTemplateChild("PART_RibbonGalleryItemsPanel") as Panel;

            resizeThumb = GetTemplateChild(PART_RibbonGalleryThumbName) as Thumb;

            if (resizeThumb != null)
            {
                resizeThumb.DragDelta += OnThumbDragDelta;
            }

            resizePanel = GetTemplateChild(PART_RGResizablePanelName) as Panel;

            base.OnApplyTemplate();
        }

        protected override void OnItemsChanged(NotifyCollectionChangedEventArgs e)
        {
            base.OnItemsChanged(e);

            if (e.Action == NotifyCollectionChangedAction.Add || e.Action == NotifyCollectionChangedAction.Remove)
            {
                CurrentIndex = 0;
            }
        }

        #endregion

        #region public Methods
        #endregion

        #region Internal Methods
        #endregion

        #region Private Methods

        /// <summary>
        /// Closes the drop-down if it's open.
        /// </summary>
        private void CloseDropDown()
        {
            if (IsDropDownOpen)
            {
                IsDropDownOpen = false;
            }

            ReleaseMouseCapture();

            Mouse.Capture(null);
        }

        /// <summary>
        /// Initializes all commands.
        /// </summary>
        private void RegisterCommands()
        {
            LineDownCommand = new Command(OnLineDownCommandExecuted);

            LineUpCommand = new Command(OnLineUpCommandExecuted);

            OpenDropDownCommand = new Command(OnOpenDropDownCommandExecuted);
        }

        /// <summary>
        /// Invoked when LineDown button is pressed.
        /// </summary>
        private void OnLineDownCommandExecuted()
        {
            if (LineDownCommand.CanExecute)
            {
                CurrentIndex++;
                UpdateCanExecuteState();
            }
        }

        /// <summary>
        /// Invoked when LineUp button is pressed.
        /// </summary>
        private void OnLineUpCommandExecuted()
        {
            if (LineUpCommand.CanExecute)
            {
                CurrentIndex--;
                UpdateCanExecuteState();
            }
        }

        /// <summary>
        /// Invoked when popup window is requested to be open.
        /// </summary>
        private void OnOpenDropDownCommandExecuted()
        {
            if (!IsDropDownOpen)
            {
                IsDropDownOpen = true;

                if (resizePanel != null) 
                {
                    resizePanel.SetValue(Panel.HeightProperty, double.NaN);
                }
            }
        }

        /// <summary>
        /// Updates execution state of up and down buttons.
        /// </summary>
        private void UpdateCanExecuteState()
        {
            if (ItemsSource == null)
            {
                LineUpCommand.CanExecute = false;
                LineDownCommand.CanExecute = false;
            }
            else
            {
                LineUpCommand.CanExecute = CurrentIndex > 0;
                remainder = Items.Count % VisibleItemsCount;
                result=(int)(Items.Count / VisibleItemsCount);
                LineDownCommand.CanExecute = remainder != 0 ? CurrentIndex < result : CurrentIndex != result - 1;
            }

        }

        private void UpdateOpenDropDownCommandExecutionState()
        {
            bool canExecute = false;

            foreach (RibbonGallery gallery in DropDownGalleries)
            {
                canExecute = canExecute | gallery.ItemContainerGenerator.Status == GeneratorStatus.ContainersGenerated ? true : false;
            }
            OpenDropDownCommand.CanExecute = canExecute;
        }
        #endregion

        #region Event Handlers

        /// <summary>
        /// Invoked whenever Thumb control raises its DragDeltaEvent event.
        /// </summary>
        /// <param name="sender">Owner of the event.</param>
        /// <param name="e">Event data for the event.</param>
        private void OnThumbDragDelta(object sender, DragDeltaEventArgs e)
        {
            e.Handled = true;

            if (resizePanel != null) 
            {
                double height = 25.0;
                if (!double.IsNaN(resizePanel.ActualHeight)) 
                {
                    height = resizePanel.ActualHeight;
                }
                
                height += e.VerticalChange;

                if (height >= MinDropDownHeight && height <= MaxDropDownHeight)
                {
                    resizePanel.Height = height;
                }
            }
        }


        /// <summary>
        /// Invoked when this control looses mouse capture.
        /// </summary>
        /// <param name="sender">Owner of the event.</param>
        /// <param name="e">Event data for the event.</param>
        private void OnMouseDownOutsideCaptured(object sender, MouseButtonEventArgs e)
        {
            if (IsDropDownOpen)
            {
                CloseDropDown();
            }
        }

        /// <summary>
        /// Occurs when items are added or deleted
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void OnDropDownGalleriesCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
        {
            if (e.Action == NotifyCollectionChangedAction.Add)
            {
                foreach (RibbonGallery gallery in e.NewItems)
                {
                    if (gallery != null)
                    {
                        gallery.ParentRibbonGallery = this;
                    }
                    if (IsDownGalleriesPanelAvaliable && !dropDownGalleriesPanel.Children.Contains(gallery))
                    {
                        dropDownGalleriesPanel.Children.Add(gallery);
                    }
                }
            }
        }

        /// <summary>
        /// Occurs when the element is laid out, rendered, and ready for interaction. 
        /// (Inherited from FrameworkElement.)
        /// </summary>
        /// <param name="sender">Owner of the event.</param>
        /// <param name="e">Event data for the event.</param>
        private void OnRibbonGalleryLoaded(object sender, RoutedEventArgs e)
        {
            //Loaded -= OnRibbonGalleryLoaded;

            if (!IsDownGalleriesPanelAvaliable) { return; }

            for (int i = 0; i < DropDownGalleries.Count; i++)
            {
                RibbonGallery gallery = DropDownGalleries[i];

                if (!dropDownGalleriesPanel.Children.Contains(gallery))
                {
                    dropDownGalleriesPanel.Children.Add(gallery);
                }
            }

            UpdateCanExecuteState();
        }

        #endregion

        #region Fields

        private const string PART_RibbonGalleryPanelName = "PART_RibbonGalleryPanel",
                             PART_UpButtonName = "PART_UpButton",
                             PART_DownButtonName = "PART_DownButton",
                             PART_ThirdButtonName = "PART_ThirdButton",
                             PART_RibbonGalleryPopupName = "PART_RibbonGalleryPopup",
                             PART_RibbonGalleryThumbName = "PART_RibbonGalleryThumb",
                             PART_RGResizablePanelName = "PART_RGResizablePanel";

        private Panel dropDownGalleriesPanel, resizePanel;

        private Thumb resizeThumb = null;
        
        private System.Windows.Controls.Primitives.ButtonBase _upButton, _downButton, _thirdButton;

        private Popup _popup;

        private RibbonGallery _parentRibbonGallery = null;

        int remainder = 0, result=0;

        internal RibbonGallery ParentRibbonGallery
        {
            get
            {
                return _parentRibbonGallery;
            }
            set
            {
                if (this._parentRibbonGallery != null)
                {
                    BindingOperations.ClearBinding(this, RibbonGallery.ItemContainerStyleProperty);
                }

                this._parentRibbonGallery = value;
            }
        }

        #endregion

        #region Events
        #endregion

        #region Commands

        /// <summary>
        /// Gets or sets a command which is executed when LineDown button is pressed.
        /// </summary>
        internal Command LineDownCommand
        {
            get { return (Command)GetValue(LineDownCommandProperty); }
            set { SetValue(LineDownCommandProperty, value); }
        }

        // Using a DependencyProperty as the backing store for LineDownCommand.  This enables animation, styling, binding, etc...
        internal static readonly DependencyProperty LineDownCommandProperty =
            DependencyProperty.Register("LineDownCommand", typeof(Command), typeof(RibbonGallery));

        /// <summary>
        /// Gets or sets a command which is executed when LineUp button is pressed.
        /// </summary>
        /// 
        internal Command LineUpCommand
        {
            get { return (Command)GetValue(LineUpCommandProperty); }
            set { SetValue(LineUpCommandProperty, value); }
        }

        // Using a DependencyProperty as the backing store for LineUpCommand.  This enables animation, styling, binding, etc...
        internal static readonly DependencyProperty LineUpCommandProperty =
            DependencyProperty.Register("LineUpCommand", typeof(Command), typeof(RibbonGallery));

        /// <summary>
        /// Gets or sets a command which is executed when the drop-down open is requsted,
        /// </summary>
        internal Command OpenDropDownCommand
        {
            get { return (Command)GetValue(OpenDropDownCommandProperty); }
            set { SetValue(OpenDropDownCommandProperty, value); }
        }

        // Using a DependencyProperty as the backing store for OpenDropDownCommand.  This enables animation, styling, binding, etc...
        internal static readonly DependencyProperty OpenDropDownCommandProperty =
            DependencyProperty.Register("OpenDropDownCommand", typeof(Command), typeof(RibbonGallery));

        #endregion

        #region IRibbonControl Implementation

        /// <summary>
        /// Gets a boolean value indicating whether the contol's size is large
        /// </summary>
        public bool IsLarge
        {
            get { return true; }
        }

        #endregion
    }
}


